﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using XNAGuiLib.Core.Utilities;

namespace XNAGuiLib.Core.Components
{
    public class Frame : GIComponent
    {
        #region Frame Protected Field - _rcm
        protected ResourceContentManager _rcm;
        #endregion 

        #region Frame Protected Field - _assetPrefix
        protected string _assetPrefix;
        #endregion

        #region Frame Protected Field - _assetSuffix
        protected string _assetSuffix;
        #endregion



        #region Frame Public Field - Bounds
        /// <summary>
        /// gets or sets the bounds of this frame
        /// </summary>
        public new Vector2 Bounds
        {
            get { return new Vector2(this._width, this._height); }
            set { this.Resize((int)value.X, (int)value.Y); }
        }
        #endregion


        #region Frame Public Field - Corner_Top_Left
        /// <summary>
        /// gets or sets the top left corner GIComponent
        /// </summary>
        public GIComponent Corner_Top_Left
        {
            get { return this._gics[0]; }
            set
            {
                value.Owner = this;
                this._gics[0] = value;
            }
        }
        #endregion

        #region Frame Public Field - Corner_Top_Right
        /// <summary>
        /// gets or sets the top right corner GIComponent
        /// </summary>
        public GIComponent Corner_Top_Right
        {
            get { return this._gics[1]; }
            set
            {
                value.Owner = this;
                this._gics[1] = value;
            }
        }
        #endregion

        #region Frame Public Field - Corner_Bottom_Left
        /// <summary>
        /// gets or sets the bottom left corner GIComponent
        /// </summary>
        public GIComponent Corner_Bottom_Left
        {
            get { return this._gics[2]; }
            set
            {
                value.Owner = this;
                this._gics[2] = value;
            }
        }
        #endregion

        #region Frame Public Field - Corner_Bottom_Right
        /// <summary>
        /// gets or sets the bottom right corner GIComponent
        /// </summary>
        public GIComponent Corner_Bottom_Right
        {
            get { return this._gics[3]; }
            set
            {
                value.Owner = this;
                this._gics[3] = value;
            }
        }
        #endregion

        #region Frame Public Field - Border_Top
        /// <summary>
        /// gets or sets the top border GIComponent
        /// </summary>
        public GIComponent Border_Top
        {
            get { return this._gics[4]; }
            set
            {
                value.Owner = this; 
                this._gics[4] = value;
            }
        }
        #endregion

        #region Frame Public Field - Border_Bottom
        /// <summary>
        /// gets or sets the bottom border GIComponent
        /// </summary>
        public GIComponent Border_Bottom
        {
            get { return this._gics[5]; }
            set
            {
                value.Owner = this;
                this._gics[5] = value;
            }
        }
        #endregion

        #region Frame Public Field - Border_Left
        /// <summary>
        /// gets or sets the left border GIComponent
        /// </summary>
        public GIComponent Border_Left
        {
            get { return this._gics[6]; }
            set
            {
                value.Owner = this;
                this._gics[6] = value;
            }
        }
        #endregion

        #region Frame Public Field - Border_Right
        /// <summary>
        /// gets or sets the right border GIComponent
        /// </summary>
        public GIComponent Border_Right
        {
            get { return this._gics[7]; }
            set
            {
                value.Owner = this;
                this._gics[7] = value;
            }
        }
        #endregion

        #region Frame Public Field - Label_Title
        /// <summary>
        /// gets or sets the top border GIComponent
        /// </summary>
        public Label Label_Title
        {
            get { return (Label)this._gics[8]; }
            set
            {
                value.Owner = this;
                this._gics[8] = value;
            }
        }
        #endregion


        #region Frame Public Field - FrameHeadSize
        protected Enums.FrameHeadStyle _frameHeadSize;
        /// <summary>
        /// gets or sets the size type for the headline of the frame (normal = default)
        /// </summary>
        public Enums.FrameHeadStyle FrameHeadSize
        {
            get { return this._frameHeadSize; }
            set
            {
                this._frameHeadSize = value;
                switch (value)
                {
                    case Enums.FrameHeadStyle.Normal:
                        _assetSuffix = "";
                        break;
                    case Enums.FrameHeadStyle.Medium:
                        _assetSuffix = "_medium";
                        break;
                    case Enums.FrameHeadStyle.Large:
                        _assetSuffix = "_large";
                        break;
                }

                ReloadFrameHead();
            }
        }
        #endregion


        #region Frame Public Field - Title
        protected string _title;
        /// <summary>
        /// gets or sets the title text to be drawn on medium and large frame head size
        /// </summary>
        public string Title
        {
            get { return this._title; }
            set
            {
                this._title = value;
                this.Label_Title.TextValue = value;
            }
        }
        #endregion

        #region Frame Public Field - TitleColor
        protected Color _titleColor;
        /// <summary>
        /// gets or sets the color in which the title is drawn
        /// </summary>
        public Color TitleColor
        {
            get { return this._titleColor; }
            set
            {
                this._titleColor = value;
                this.Label_Title.TextColor = value;
            }
        }
        #endregion

        #region Frame Public Field - Visible
        public new bool Visible
        {
            get { return this._visible; }
            set
            {
                this._visible = value;
                foreach (GIComponent gic in _gics)
                {
                    gic.Visible = value;
                }
            }
        }
        #endregion


        /* Component mapping for the Frame Element
         * =======================================
         * [0]  Corner Top Left
         * [1]  Corner Top Right
         * [2]  Corner Bottom Left
         * [3]  Corner Bottom Right
         * [4]  Border Top
         * [5]  Border Bottom
         * [6]  Border Left
         * [7]  Border Right
         * [8]  Label Title
         * 
         */
        public Frame(Game game, ResourceContentManager rcm, string assetPrefix, int width, int height)
            : base(game)
        {
            // setting the protected fields
            #region Setting Protected Fields
            this._rcm = rcm;
            this._assetPrefix = assetPrefix;
            this._height = height;
            this._width = width;
            #endregion

            // adding corner components
            #region Adding Corner Components
            GIComponent crn_top_left = this.CreateGIC("crn_top_left" + this._assetSuffix);
            crn_top_left.RelativePosition = new Vector2(0, 0);

            GIComponent crn_top_right = this.CreateGIC("crn_top_right" + this._assetSuffix);
            crn_top_right.RelativePosition = new Vector2(width - crn_top_right.Width, 0);

            GIComponent crn_bottom_left = this.CreateGIC("crn_bottom_left");
            crn_bottom_left.RelativePosition = new Vector2(0, height - crn_bottom_left.Height);

            GIComponent crn_bottom_right = this.CreateGIC("crn_bottom_right");
            crn_bottom_right.RelativePosition = new Vector2(width - crn_bottom_right.Width, height - crn_bottom_right.Height);


            this.Add(crn_top_left);
            this.Add(crn_top_right);
            this.Add(crn_bottom_left);
            this.Add(crn_bottom_right);     
            #endregion 

            // adding border components
            #region Adding Border Components
            int brd_thickness = _rcm.Load<Texture2D>(this._assetPrefix + "brd_top" + this._assetSuffix).Height;
            GIComponent brd_top = this.CreateGIC("brd_top" + this._assetSuffix, new Rectangle(0, 0, width - (crn_top_left.Width + crn_top_right.Width), brd_thickness));
            brd_top.RelativePosition = new Vector2(crn_top_left.Width, 0);

            brd_thickness = _rcm.Load<Texture2D>(this._assetPrefix + "brd_right").Width;
            GIComponent brd_right = this.CreateGIC("brd_right", new Rectangle(0, 0, brd_thickness, height - (crn_top_right.Height + crn_bottom_right.Height)));
            brd_right.RelativePosition = new Vector2(crn_top_left.Width + brd_top.Width, crn_top_right.Height);

            brd_thickness = _rcm.Load<Texture2D>(this._assetPrefix + "brd_bottom").Height;
            GIComponent brd_bottom = this.CreateGIC("brd_bottom", new Rectangle(0, 0, width - (crn_bottom_left.Width + crn_bottom_right.Width), brd_thickness));
            brd_bottom.RelativePosition = new Vector2(crn_bottom_left.Width, height - brd_thickness);

            brd_thickness = _rcm.Load<Texture2D>(this._assetPrefix + "brd_left").Width;
            GIComponent brd_left = this.CreateGIC("brd_left", new Rectangle(0, 0, brd_thickness, height - (crn_top_left.Height + crn_bottom_left.Height)));
            brd_left.RelativePosition = new Vector2(0, crn_top_left.Height);

            this.Add(brd_top);
            this.Add(brd_bottom);
            this.Add(brd_left);
            this.Add(brd_right);
            #endregion 

            // adding title label component
            #region Adding Label_Title Component
            Label lbl_title = this.CreateLabel_Title("Title", brd_top.Width, brd_top.Height, crn_top_left.Width, Color.White);
            this.Add(lbl_title);
            #endregion 

            // setting the head size to default (normal)
            #region Setting Head Size
            this.FrameHeadSize = Enums.FrameHeadStyle.Normal;
            #endregion
        }



        #region Frame Protected Method - ReloadFrameHead()
        /// <summary>
        /// reloads the frames head area with the correct style assets (normal, medium, large)
        /// </summary>
        protected void ReloadFrameHead()
        {
            GIComponent crn_top_left = this.CreateGIC("crn_top_left" + this._assetSuffix);
            crn_top_left.RelativePosition = new Vector2(0, 0);
            this.Corner_Top_Left = crn_top_left;

            GIComponent crn_top_right = this.CreateGIC("crn_top_right" + this._assetSuffix);
            crn_top_right.RelativePosition = new Vector2(this._width - crn_top_right.Width, 0);
            this.Corner_Top_Right = crn_top_right;

            int brd_thickness = _rcm.Load<Texture2D>(this._assetPrefix + "brd_top" + this._assetSuffix).Height;
            GIComponent brd_top = this.CreateGIC("brd_top" + this._assetSuffix, new Rectangle(0, 0, this._width - (crn_top_left.Width + crn_top_right.Width), brd_thickness));
            brd_top.RelativePosition = new Vector2(crn_top_left.Width, 0);
            this.Border_Top = brd_top;

            brd_thickness = _rcm.Load<Texture2D>(this._assetPrefix + "brd_right").Width;
            GIComponent brd_right = this.CreateGIC("brd_right", new Rectangle(0, 0, brd_thickness, this._height - (crn_top_right.Height + this.Corner_Bottom_Right.Height)));
            brd_right.RelativePosition = new Vector2(crn_top_left.Width + brd_top.Width, crn_top_right.Height);
            this.Border_Right = brd_right;

            brd_thickness = _rcm.Load<Texture2D>(this._assetPrefix + "brd_left").Width;
            GIComponent brd_left = this.CreateGIC("brd_left", new Rectangle(0, 0, brd_thickness, this._height - (crn_top_left.Height + this.Corner_Bottom_Left.Height)));
            brd_left.RelativePosition = new Vector2(0, crn_top_left.Height);
            this.Border_Left = brd_left;

            this.Label_Title = this.CreateLabel_Title("Title", brd_top.Width, brd_top.Height, crn_top_left.Width, Color.White);
        }
        #endregion

        #region Frame Protected Method - Resize(int width, int height)
        /// <summary>
        /// resizes the frame and the necessary children on it
        /// </summary>
        /// <param name="width">width to set for the frame</param>
        /// <param name="height">height to set for the frame</param>
        protected override void Resize(int width, int height)
        {
            this._width = width;
            this._height = height;

            // reset relative position for corner top left
            this.Corner_Top_Right.RelativePosition = new Vector2(this._width - this.Corner_Top_Right.Width, 0);
            // reset relative position for corner bottom left
            this.Corner_Bottom_Left.RelativePosition = new Vector2(0, height - this.Corner_Bottom_Left.Height);
            // reset relative position for corner bottom right
            this.Corner_Bottom_Right.RelativePosition = new Vector2(this._width - this.Corner_Bottom_Right.Width, this._height - this.Corner_Bottom_Right.Height);
            // reset size and relative position for border top
            this.Border_Top.ContentComponents[0].Rectangle = new Rectangle(0, 0, this._width - (this.Corner_Top_Left.Width + this.Corner_Top_Right.Width), this.Border_Top.Height);
            this.Border_Top.RelativePosition = new Vector2(this.Corner_Top_Left.Width, 0);
            this.Border_Top.Bounds = new Vector2(this._width - (this.Corner_Top_Left.Width + this.Corner_Top_Right.Width), this.Border_Top.Height);
            // reset size and relative position for border bottom
            this.Border_Bottom.ContentComponents[0].Rectangle = new Rectangle(0, 0, this._width - (this.Corner_Bottom_Left.Width + this.Corner_Bottom_Left.Width), this.Border_Bottom.Height);
            this.Border_Bottom.RelativePosition = new Vector2(this.Corner_Bottom_Left.Width, this._height - this.Border_Bottom.Height);
            this.Border_Bottom.Bounds = new Vector2(this._width - (this.Corner_Bottom_Left.Width + this.Corner_Bottom_Left.Width), this.Border_Bottom.Height);
            // reset size and relative position for bottom right
            this.Border_Right.ContentComponents[0].Rectangle = new Rectangle(0, 0, this.Border_Right.Width, this._height - (this.Corner_Top_Left.Height + this.Corner_Bottom_Right.Height));
            this.Border_Right.RelativePosition = new Vector2(this._width - this.Border_Right.Width, this.Corner_Top_Right.Height);
            this.Border_Right.Bounds = new Vector2(this.Border_Right.Width, this._height - (this.Corner_Top_Left.Height + this.Corner_Bottom_Right.Height));
            // reset size and relative position for bottom left
            this.Border_Left.ContentComponents[0].Rectangle = new Rectangle(0, 0, this.Border_Left.Width, this._height - (this.Corner_Top_Left.Height + this.Corner_Bottom_Left.Height));
            this.Border_Left.RelativePosition = new Vector2(0, this.Corner_Top_Left.Height);
            this.Border_Left.Bounds = new Vector2(this.Border_Left.Width, this._height - (this.Corner_Top_Left.Height + this.Corner_Bottom_Left.Height));

        }
        #endregion

        #region Frame Protected Method - CreateGIC(string asset)
        /// <summary>
        /// creates a GIComponent with the given asset as texture on it
        /// </summary>
        /// <param name="asset">name of the asset (in the resource file) to load</param>
        /// <returns>a GIComponent with a Texture object on it drawing the asset</returns>
        protected GIComponent CreateGIC(string asset)
        {
            ContentComponent cc = new ContentComponent(_rcm.Load<Texture2D>(this._assetPrefix + asset));
            GIComponent gic = Provider.GetInstance(this._game).CreateGIC();
            gic.Add(cc);

            return gic;
        }
        #endregion

        #region Frame Protected Method - CreateGIC(string asset, Rectangle rect)
        /// <summary>
        /// creates a GIComponent with the given asset as texture on it
        /// </summary>
        /// <param name="asset">name of the asset (in the resource file) to load</param>
        /// <param name="rect">rectangle on which the asset will be scaled</param>
        /// <returns>a GIComponent with a Texture object on it drawing the asset scaled to the rectangle</returns>
        protected GIComponent CreateGIC(string asset, Rectangle rect)
        {
            ContentComponent cc = new ContentComponent(_rcm.Load<Texture2D>(this._assetPrefix + asset), rect);
            GIComponent gic = Provider.GetInstance(this._game).CreateGIC();
            gic.Add(cc);

            return gic;
        }
        #endregion

        #region Frame Protected Method - CreateLabel_Title(string title, int width, int height, int x, Color titleColor)
        /// <summary>
        /// creates a Label object with the given text, width, height and distance to the left edge of the frame
        /// </summary>
        /// <param name="title">text to render as title</param>
        /// <param name="width">width of the label object (may affect background and background decoration)</param>
        /// <param name="height">height og the label object</param>
        /// <param name="x">distance to the left edge</param>
        /// <param name="titleColor">color for the title text</param>
        /// <returns>a label object with the given attributes</returns>
        protected Label CreateLabel_Title(string title, int width, int height, int x, Color titleColor)
        {
            Label lbl_title = new Label(this._game, this._rcm, title, width, height);
            lbl_title.TextColor = titleColor;
            lbl_title.RelativePosition = new Vector2(x, 4);
            lbl_title.BackgroundOpaque = 0;

            if (_frameHeadSize == Enums.FrameHeadStyle.Normal)
                lbl_title.Visible = false;
            else
                lbl_title.Visible = true;

            return lbl_title;
        }
        #endregion


        #region Frame Public Method - Opaque(int percentage)
        /// <summary>
        /// sets the opacity of the frame and its children
        /// </summary>
        /// <param name="percentage">value of opacity</param>
        public new void Opaque(int percentage)
        {
            if (percentage >= 0 && percentage <= 100)
            {
                foreach (GIComponent gic in _gics)
                {
                    gic.Opaque(percentage);
                }
            }
        }
        #endregion
    }
}